//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Globalization;

namespace OpenLS.Spreadsheet.Parsing
{
    class ExplicitCharacterCreator : TokenCreator
    {
        public override char[] FirstChars()
        {
            return new char[] { '\'' };
        }
        public override Token Match(Lexer l)
        {
            Len = 3;
            bool isNum = false; ;
            if (l.CurrentCharAt(1) == '\\')
            {
                if (CharTypeManager.IsNumeric(l.CurrentCharAt(2)))
                {
                    Len = 4;
                    isNum = true;
                    while (CharTypeManager.IsNumeric(l.CurrentCharAt(Len - 2)))
                    {
                        Len++;
                    }
                    Len--;
                }
                else
                {
                    Len = 4;
                }
            }
            if (isNum)
            {
                string s = l.Substring(l.Position + 2, Len - 3);
                int i = int.Parse(s, NumberFormatInfo.InvariantInfo);
                return new ExplicitCharacter((char)i);
            }
            if (Len - 1 > l.MaxIndex)
                return new InvalidToken(l.EndString());
            if (l.CurrentCharAt(Len - 1) != '\'')
            {
                for (Len--; !(l.CurrentCharAt(Len - 1) == '\'' && l.CurrentCharAt(Len) != '\'' && l.CurrentCharAt(Len-2) != '\'' ); Len++)
                {
                    if (Len > l.MaxIndex)
                        return new InvalidToken(l.EndString());
                }
                //Len++;
                string str = l.Substring(l.Position + 1, Len - 2).Replace("''", "'");
                SingleQuoteIdentifier id = new SingleQuoteIdentifier(str);
                return id;
            }
            if (Len == 3)
                return new ExplicitCharacter(l.Substring(l.Position + 1, 1)[0]);
            if (Len == 4)
            {
                char cc = l.Substring(l.Position + 2, Len - 1)[0];
                char newChar;
                switch (cc)
                {
                    case '\'': newChar = '\''; break;
                    case '"': newChar = '"'; break;
                    case '0': newChar = '\0'; break;
                    case 'a': newChar = '\a'; break;
                    case 'b': newChar = '\b'; break;
                    case 'f': newChar = '\f'; break;
                    case 'n': newChar = '\n'; break;
                    case 'r': newChar = '\r'; break;
                    case 't': newChar = '\t'; break;
                    case 'v': newChar = '\v'; break;
                    case '\\': newChar = '\\'; break;
                    case 'u':
                        string s1 = l.Substring(l.Position + Len - 1, 4);
                        int i = (int)Numeric.LongHexa(s1);
                        newChar = ((char)i);
                        Len += 4;
                        break; // TODO: test
                    case 'x':
                        int addLen = 1;
                        while (l[l.Position + Len - 1 + addLen] != '\'')
                            addLen++;
                        string ss1 = l.Substring(l.Position + Len - 1, addLen);
                        int ii = (int)Numeric.LongHexa(ss1);
                        newChar = (char)ii;
                        Len += addLen;
                        break;

                    default: throw new InvalidCharacterException(cc);
                }
                return new ExplicitCharacter(newChar);
            }
            throw new InvalidCharacterException(l.CurrentCharAt(1));
        }
        int Len;
        public override int MatchSize()
        {
            return Len;
        }
    }

    internal class InvalidToken : Token
    {
        private string _value;

        public InvalidToken(string endString)
        {
            _value = endString;
        }

        public override string ToString()
        {
            return _value;
        }

        public override TokenId Type
        {
            get { return TokenId.Invalid; }
        }
    }
}